package com.wlsk.license.common.execl;


import cn.idev.excel.EasyExcel;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.write.metadata.WriteSheet;
import com.wlsk.license.common.exception.BusinessException;
import com.wlsk.license.common.utils.ValidationUtils;
import com.wlsk.license.dto.BaseDto;
import com.wlsk.license.dto.BasePageReqDto;
import com.wlsk.license.dto.PageResultDto;
import org.springframework.util.StopWatch;

import java.util.List;
import java.util.Objects;

/**
 * <p>@Description : Excel分页导出服务</p>
 * <p>@Author : Zhangbin.Liu </p>
 * <p>@Date : 2025/02/18 16:53 </p>
 */
public abstract class AbstractExcelPageExportService<DATA extends BaseDto, PARAM extends BasePageReqDto> extends AbstractBaseExcelExportService<DATA, PARAM> {

    /**
     * 获取数据
     *
     * @param param
     * @return
     */
    protected abstract PageResultDto<DATA> data(PARAM param);

    /**
     * 导出，返回下载链接
     *
     * @param param
     * @return
     */
    public final String export(PARAM param) {
        param.valid();
        StopWatch stopWatch = new StopWatch("导出" + getName(param));
        stopWatch.start();
        param.setPageNum(1);
        String path = this.getPath();
        String localFileName = getLocalFileName(param, path);
        ExcelWriter writer = null;
        try {
            writer = EasyExcel.write(localFileName, this.getDataClass()).build();
            int sheetIndex = 1;

            WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex - 1, getName(param) + "-" + sheetIndex).build();
            PageResultDto<DATA> data = data(param);

            ValidationUtils.isTrue(data.getTotalCount() > 0, "导出数据不能为空");
            ValidationUtils.isTrue(param.getPageSize() <= 5000, "每页最多查询5000条数据");
            ValidationUtils.isTrue(param.getPageSize() % 10 == 0, "每页查询记录数必须是10的倍数");
            ValidationUtils.isTrue(data.getTotalCount() <= getLimit() || getLimit() == 0, "共" + data.getTotalCount() + "条记录，最多导出" + getLimit() + "条");

            //已写记录数
            int writeCount = 0;

            writer.write(data.getContent(), writeSheet);
            writeCount = writeCount + data.getContent().size();

            long totalPages = data.getTotalPages();
            if (totalPages > 1) {
                List<DATA> tmpData = null;
                for (int i = 2; i <=totalPages; i++) {
                    param.setPageNum(i);
                    data = data(param);
                    int tmpWriteCount = writeCount + data.getContent().size();
                    if (tmpWriteCount > 60000) {
                        int diffWriteCount = tmpWriteCount - 60000;
                        writer.write(data.getContent().subList(0, diffWriteCount), writeSheet);
                        sheetIndex = sheetIndex + 1;
                        writeSheet = EasyExcel.writerSheet(sheetIndex - 1, getName(param) + "-" + sheetIndex).build();
                        tmpData = data.getContent().subList(diffWriteCount, data.getContent().size());
                        writer.write(tmpData, writeSheet);
                        writeCount = tmpData.size();
                    } else {
                        writer.write(data.getContent(), writeSheet);
                        writeCount = writeCount + data.getContent().size();
                        if (tmpWriteCount == 60000) {
                            sheetIndex = sheetIndex + 1;
                            writeSheet = EasyExcel.writerSheet(sheetIndex - 1, getName(param) + "-" + sheetIndex).build();
                        }
                    }
                }
            }
        } catch (BusinessException e) {
            super.deleteLocalFile(localFileName);
            throw new BusinessException(e.getMessage());
        } catch (Exception e) {
            super.deleteLocalFile(localFileName);
            log.error("导出{}excel错误：{}", getName(param), e.getMessage(), e);
            throw new BusinessException("导出" + getName(param) + "数据错误");
        } finally {
            if (Objects.nonNull(writer)) {
                writer.finish();
            }
        }
        String downloadUrl = super.uploadOss(localFileName);
        stopWatch.stop();
        log.info("导出{},耗时:{}秒................", localFileName, stopWatch.getTotalTimeSeconds());
        return downloadUrl;
    }


}
